package com.awplanet.sitegen;

import com.awplanet.sitegen.data.*;
import com.awplanet.sitegen.template.Template;
import com.awplanet.sitegen.utils.IOUtils;
import com.awplanet.sitegen.utils.RandomUtils;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;

import javax.swing.*;
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * User: a_polyakov
 */
public class SiteGen extends DefaultBoundedRangeModel implements Runnable {

	private String path;
	private boolean includeTest;
	private boolean includeWordData;
	private boolean includeUsaData;
	private boolean includeMoneyGramData;
	private String dirName;
	private int indexPageSize;
	private int countryPageSize;
	private int cityPageSize;
	private int minRandomLink;
	private int maxRandomLink;
	private int minRandomText;
	private int maxRandomText;

	private Template indexTemplate;
	private boolean indexTemplateUsePageList;
//	private boolean indexTemplateUseRandomText;
	private Template indexItemTemplate;
	private Template countryTemplate;
	private boolean countryTemplateUsePageList;
//	private boolean countryTemplateUseRandomText;
	private Template countryItemTemplate;
	private Template cityTemplate;
	private boolean cityTemplateUsePageList;
	private boolean cityTemplateUseRandomCityLinkList;
//	private boolean cityTemplateUseRandomText;
	private Template cityItemTemplate;
	private Template departmentServiceTemplate;
	private Template departmentWorkTimeTemplate;
	private Template pageButtonTemplate;
	private Template pageSelectButtonTemplate;
	private Template randomCityLinkTemplate;

	public SiteGen(String path, boolean includeTest, boolean includeWordData, boolean includeUsaData, boolean includeMoneyGramData, String dirName, int indexPageSize, int countryPageSize, int cityPageSize, int minRandomLink, int maxRandomLink, int minRandomText, int maxRandomText) {
		this.path = path;
		this.includeTest = includeTest;
		this.includeWordData = includeWordData;
		this.includeUsaData = includeUsaData;
		this.includeMoneyGramData = includeMoneyGramData;
		this.dirName = dirName;
		this.indexPageSize = indexPageSize;
		this.countryPageSize = countryPageSize;
		this.cityPageSize = cityPageSize;
		this.minRandomLink = minRandomLink;
		this.maxRandomLink = maxRandomLink;
		this.minRandomText = minRandomText;
		this.maxRandomText = maxRandomText;
	}

	private static void modelAppendFile(Model model, String dataFilePath, EDataFormat dataFormat) {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(dataFilePath));
			String line = reader.readLine();
			while (line != null) {
				dataFormat.modelAppendLine(model, line);
				line = reader.readLine();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private List<String> readTextList(String textFilePath) {
		List<String> textList = new ArrayList<String>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(textFilePath));
			String line = reader.readLine();
			while (line != null) {
				textList.add(line);
				line = reader.readLine();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return textList;
	}

	private void makingIndex(Map<String, String> workMap, Map<String, Object> hideAttr, String dirName, Model model, int indexPageSize) throws IOException {
		Iterator<Country> iterator = model.getCountryMap().values().iterator();
		workMap.put("index.url", "index.html");
		for (int page = 1; iterator.hasNext(); page++) {
			List<Country> indexItemList=new ArrayList<Country>();
			hideAttr.put("indexItemList", indexItemList);
			for (int i = 0; iterator.hasNext() && (indexTemplateUsePageList == false || indexPageSize == 0 || i < indexPageSize); i++) {
				final Country country = iterator.next();
				indexItemList.add(country);
			}
			if (indexTemplateUsePageList) {
				hideAttr.put("pageButtonUrl", "index");
				hideAttr.put("pageButtonPage", page);
				hideAttr.put("pageButtonSize", model.getCountryMap().size());
				hideAttr.put("pageButtonPageSize", indexPageSize);
			}
			String fileName = "index";
			if (page > 1)
				fileName += page;
			FileOutputStream indexOutputStream=IOUtils.getFileOutputStream(new File(dirName, fileName + ".html"));
			indexTemplate.write(indexOutputStream, workMap, hideAttr);
			indexOutputStream.close();
		}
	}

	private void makingCountry(Map<String, String> workMap, Map<String, Object> hideAttr, String dirName, Country country, int countryPageSize) throws IOException {
		workMap.putAll(country);
		Iterator<City> iterator = country.getCityMap().values().iterator();
		for (int page = 1; iterator.hasNext(); page++) {
			List<City> countryItemList=new ArrayList<City>();
			hideAttr.put("countryItemList", countryItemList);
			for (int i = 0; iterator.hasNext() && (countryTemplateUsePageList == false || countryPageSize == 0 || i < countryPageSize); i++) {
				final City city = iterator.next();
				countryItemList.add(city);
			}
			if (countryTemplateUsePageList) {
				hideAttr.put("pageButtonUrl", "index");
				hideAttr.put("pageButtonPage", page);
				hideAttr.put("pageButtonSize", country.getCityMap().size());
				hideAttr.put("pageButtonPageSize", countryPageSize);
			}
			workMap.put("index.url", "../index.html");
			workMap.put("country.url", "index.html");
			String fileName = country.getFileName() + "/index";
			if (page > 1)
				fileName += page;
			FileOutputStream countryOutputStream=IOUtils.getFileOutputStream(new File(dirName, fileName + ".html"));
			countryTemplate.write(countryOutputStream, workMap, hideAttr);
			countryOutputStream.close();
		}
	}

	private void makingCity(Map<String, String> workMap, Map<String, Object> hideAttr, String dirName, Model model, Country country, City city, int cityPageSize) throws IOException {
		Iterator<Department> iterator = city.getDepartmentMap().values().iterator();
		workMap.putAll(country);
		workMap.putAll(city);
		workMap.put("index.url", "../index.html");
		workMap.put("country.url", "index.html");
		workMap.put("city.url", city.getFileName() + ".html");
		for (int page = 1; iterator.hasNext(); page++) {
			List<Department> cityItemList=new ArrayList<Department>();
			hideAttr.put("cityItemList", cityItemList);
			for (int i = 0; iterator.hasNext() && (cityTemplateUsePageList == false || cityPageSize == 0 || i < cityPageSize); i++) {
				final Department deportment = iterator.next();
				cityItemList.add(deportment);
			}
			if (cityTemplateUsePageList) {
				hideAttr.put("pageButtonUrl", city.getFileName());
				hideAttr.put("pageButtonPage", page);
				hideAttr.put("pageButtonSize", city.getDepartmentMap().size());
				hideAttr.put("pageButtonPageSize", cityPageSize);
			}
			if (cityTemplateUseRandomCityLinkList) {
				hideAttr.put("model",model);
				hideAttr.put("country",country);
				hideAttr.put("city",city);
			}
			String fileName = country.getFileName() + "/" + city.getFileName();
			if (page > 1)
				fileName += page;
			FileOutputStream cityOutputStream = IOUtils.getFileOutputStream(new File(dirName, fileName + ".html"));
			cityTemplate.write(cityOutputStream, workMap, hideAttr);
			cityOutputStream.close();
		}
	}

	public void run() {
		long time = System.currentTimeMillis();
		setMaximum(100);
		// read template
		String s=IOUtils.readFile(path + "/resources/index.html");
		this.indexTemplate =new Template(s);
		// TODO indexTemplate.indexAttr
		this.indexTemplateUsePageList = s.indexOf("${include.pageButton.html}") > 0;
//		this.indexTemplateUseRandomText = s.indexOf("${randomText}") > 0;
		s=IOUtils.readFile(path + "/resources/indexItem.html");
		this.indexItemTemplate =new Template(s);
		setValue(1);
		s=IOUtils.readFile(path + "/resources/country.html");
		this.countryTemplate = new Template(s);
		this.countryTemplateUsePageList = s.indexOf("${include.pageButton.html}") > 0;
//		this.countryTemplateUseRandomText = s.indexOf("${randomText}") > 0;
		s=IOUtils.readFile(path + "/resources/countryItem.html");
		this.countryItemTemplate = new Template(s);
		setValue(2);
		s=IOUtils.readFile(path + "/resources/city.html");
		this.cityTemplate = new Template(s);
		this.cityTemplateUsePageList = s.indexOf("${include.pageButton.html}") > 0;
		this.cityTemplateUseRandomCityLinkList = s.indexOf("${include.randomCityLink.html}") > 0;
//		this.cityTemplateUseRandomText = s.indexOf("${randomText}") > 0;
		s=IOUtils.readFile(path + "/resources/cityItem.html");
		this.cityItemTemplate =new Template(s);
		setValue(3);
		s=IOUtils.readFile(path + "/resources/departmentService.html");
		this.departmentServiceTemplate =new Template(s);
		s=IOUtils.readFile(path + "/resources/departmentWorkTime.html");
		this.departmentWorkTimeTemplate =new Template(s);
		s=IOUtils.readFile(path + "/resources/pageButton.html");
		this.pageButtonTemplate = new Template(s);
		s=IOUtils.readFile(path + "/resources/pageSelectButton.html");
		this.pageSelectButtonTemplate = new Template(s);
		s=IOUtils.readFile(path + "/resources/randomCityLink.html");
		this.randomCityLinkTemplate = new Template(s);
		setValue(4);

		//read data
		Model model = new Model();
		if (includeTest) {
			for (int i = 1; i <= 50; i++) {
				String countryFileName = "country" + ((i < 10) ? "0" : "") + i;
				Country country = new Country(countryFileName, countryFileName);
				model.getCountryMap().put(countryFileName, country);
				for (int j = 1; j <= i; j++) {
					String cityFileName = "city" + ((j < 10) ? "0" : "") + j;
					City city = new City(cityFileName, cityFileName);
					country.getCityMap().put(cityFileName, city);
					for (int k = 1; k <= j; k++) {
						Department department = new Department("name" + k, "address" + k, "ZipCode" + k, "Flag1" + k, "phone" + k);
						city.getDepartmentMap().put("name" + k, department);
						for (int l = 1; l <= k; l++) {
							DepartmentWorkTime departmentWorkTime = new DepartmentWorkTime("day", "time");
							department.getWorkTimeList().add(departmentWorkTime);
						}
						for (int l = 1; l <= k; l++) {
							DepartmentService departmentService = new DepartmentService("service" + l);
							department.getServiceList().add(departmentService);
						}
					}
				}
			}
		}

		if (includeWordData) {
			modelAppendFile(model, path + "/resources/word2.txt", EDataFormat.WORD);
			setValue(6);
		}
		if (includeUsaData) {
			modelAppendFile(model, path + "/resources/usa2.txt", EDataFormat.WORD);
			setValue(8);
		}
		if (includeMoneyGramData) {
			modelAppendFile(model, path + "/resources/final_moneygram_formated.txt", EDataFormat.MONEYGRAM);
			setValue(10);
		}

		// read text
		List<String> textList = readTextList(path + "/resources/western_union_en.txt");
		setValue(11);

		// read additional properties
		Map<String, String> workMap = new HashMap<String, String>();
		try {
			PropertyResourceBundle resourceBundle = new PropertyResourceBundle(new FileReader(path + "/resources/additional.properties"));
			for (String key : resourceBundle.keySet()) {
				workMap.put(key, resourceBundle.getString(key));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		final Random random = new Random();

		int max = 11;
		for (Country country : model.getCountryMap().values()) {
			for (City city : country.getCityMap().values()) {
				max += city.getDepartmentMap().size();
			}
		}
		setMaximum(max + 1);

		Map<String, Object> hideAttr=new HashMap<String, Object>();
		hideAttr.put("random", random);
		hideAttr.put("indexItemTemplate", indexItemTemplate);
		hideAttr.put("countryItemTemplate", countryItemTemplate);
		hideAttr.put("cityItemTemplate", cityItemTemplate);
		hideAttr.put("departmentWorkTimeTemplate", departmentWorkTimeTemplate);
		hideAttr.put("departmentServiceTemplate", departmentServiceTemplate);
		hideAttr.put("pageButtonTemplate", pageButtonTemplate);
		hideAttr.put("pageSelectButtonTemplate", pageSelectButtonTemplate);
		hideAttr.put("randomCityLinkTemplate", randomCityLinkTemplate);
		hideAttr.put("textList", textList);
		hideAttr.put("minRandomText", minRandomText);
		hideAttr.put("maxRandomText", maxRandomText);
		hideAttr.put("minRandomLink", minRandomLink);
		hideAttr.put("maxRandomLink", maxRandomLink);

		// generate
		try {
			makingIndex(workMap, hideAttr, dirName, model, indexPageSize);
		} catch (IOException e) {
			e.printStackTrace();
		}
		for (Country country : model.getCountryMap().values()) {
			try {
				makingCountry(workMap, hideAttr, dirName, country, countryPageSize);
			} catch (IOException e) {
				e.printStackTrace();
			}
			for (City city : country.getCityMap().values()) {
				//TODO multithread
//				Runtime.getRuntime().availableProcessors()
				try {
					makingCity(workMap, hideAttr, dirName, model, country, city, cityPageSize);
				} catch (IOException e) {
					e.printStackTrace();
				}
				setValue(getValue() + city.getDepartmentMap().size());
			}
		}

		IOUtils.copy(new File(path, "web_resource"), new File(dirName));
		setValue(getValue() + 1);
		time = System.currentTimeMillis() - time;
		System.out.print("Generate complete " + time + "ms");

	}

	private String replaceAll(String source, Map<String, String> map) {
		if (map != null) {
			for (Map.Entry<String, String> entry : map.entrySet()) {
				source = Pattern.compile("${" + entry.getKey() + "}", Pattern.LITERAL).matcher(source).replaceAll(Matcher.quoteReplacement(entry.getValue()));
			}
		}
		return source;
	}
}
